package com.miyu.system.service.system.impl;

import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.system.*;
import cn.hutool.system.oshi.CpuInfo;
import cn.hutool.system.oshi.OshiUtil;
import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONArray;
import com.alibaba.fastjson2.JSONObject;
import com.alibaba.fastjson2.JSONReader;
import com.blinkfox.fenix.specification.FenixSpecification;
import com.miyu.system.dao.system.SysNoticeDao;
import com.miyu.system.dao.system.SysParamConfigDao;
import com.miyu.system.pojo.system.SysNotice;
import com.miyu.system.pojo.system.SysParamConfig;
import com.miyu.system.service.system.SystemService;
import com.miyu.system.utils.enumeration.R;
import com.miyu.system.utils.page.PageLimit;
import com.miyu.system.utils.stool.SystemStatic;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.data.domain.*;
import org.springframework.stereotype.Service;
import oshi.SystemInfo;
import oshi.hardware.GlobalMemory;
import oshi.software.os.OSFileStore;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.List;

/**
 * 系统服务impl
 * @author miyu
 * @date 2024/02/25
 */
@Slf4j
@Service
@RequiredArgsConstructor(onConstructor_ = {@Autowired})
public class SystemServiceImpl implements SystemService {
    private final SysParamConfigDao paramConfigDao;
    /**通知类*/
    private final SysNoticeDao sysNoticeDao;
    /**
     * 系统硬件信息
     * @return jsonobject
     */
    @Override
    public JSONObject systemHardwareInformation() {
        JSONObject result = new JSONObject();
        SystemInfo systemInfo = new SystemInfo();

        /** cpu信息*/
        CpuInfo cpuInfo = OshiUtil.getCpuInfo();
        /** java 信息*/
        JvmInfo jvmInfo = SystemUtil.getJvmInfo();
        RuntimeInfo runtimeInfo = SystemUtil.getRuntimeInfo();

        JSONObject jav = new JSONObject();
        jav.put("totalMemory",convertFileSize(SystemUtil.getTotalMemory()));
        jav.put("JvmSpecInfo",SystemUtil.getJvmSpecInfo());
        jav.put("JvmInfo",SystemUtil.getJvmInfo());
        jav.put("JavaSpecInfo",SystemUtil.getJavaSpecInfo());
        jav.put("JavaInfo",SystemUtil.getJavaInfo());
        jav.put("UserInfo",SystemUtil.getUserInfo());
        jav.put("HostInfo",SystemUtil.getHostInfo());

        jav.put("max", convertFileSize(runtimeInfo.getMaxMemory()));
        jav.put("free",convertFileSize( runtimeInfo.getFreeMemory()));
        jav.put("Usable", convertFileSize(runtimeInfo.getUsableMemory()));
        jav.put("total", convertFileSize(runtimeInfo.getTotalMemory()));
        /** host 信息*/
        JSONObject hostJson = getHostInfo(jvmInfo);
        /** 硬盘信息*/
        List<OSFileStore> fileStores = OshiUtil.getOs().getFileSystem().getFileStores();
        JSONArray store = new JSONArray();
        for (OSFileStore s : fileStores) {
            JSONObject st = new JSONObject();
            st.put("name", s.getName());
            st.put("type", s.getType());
            st.put("total",convertFileSize(s.getTotalSpace()));
            st.put("used", convertFileSize(s.getTotalSpace()-s.getUsableSpace()));
            st.put("free", convertFileSize(s.getFreeSpace()));
            st.put("rate", new BigDecimal(s.getFreeSpace()).divide(new BigDecimal(s.getTotalSpace()),4,RoundingMode.HALF_UP).multiply(new BigDecimal(100)).setScale(2,RoundingMode.HALF_UP)+"%");
            store.add(st);
        }

        result.put("store", store);
        result.put("cpu", cpuInfo);
        result.put("java", jav);
        result.put("hostJson", hostJson);
        log.info(result.toString());
        return result;
    }

    /**
     * 系统参数查询
     *
     * @param params
     * @return JSONArray
     */
    @Override
    public Page<SysParamConfig> querySysConfirm(JSONObject params) {
        Pageable pageable = PageLimit.pageable(params);
        return  paramConfigDao.findAll(
                FenixSpecification.of(builder ->
                        builder.andLike("paramCode",params.get("info"), StrUtil.isNotBlank(params.getString("info")))
                                .andLike("paramName",params.get("info"), StrUtil.isNotBlank(params.getString("info"))).build())
                ,pageable);
    }

    /**
     * 系统参数编辑
     *
     * @return JSONObject
     */
    @Override
    @CacheEvict(cacheNames = "system:sysParam",key="#sysParamConfig.getParamCode()" ,beforeInvocation=true)
    public JSONObject editSysConfirm(SysParamConfig sysParamConfig) {

       boolean isExists = paramConfigDao.existsByCode(sysParamConfig);
       if (isExists) {
          return R.result("-1","编码已存在");
       }else{
           paramConfigDao.saveOrUpdateByNotNullProperties(sysParamConfig);
       }
        return R.result("101");
    }

    /**
     * 系统参数删除
     *
     * @param sysParamConfig
     * @return
     */
    @Override
    @CacheEvict(cacheNames = "system:sysParam", allEntries = true,beforeInvocation=true)
    public JSONObject delSysConfirm(List<SysParamConfig> sysParamConfig) {
         paramConfigDao.deleteAllInBatch(sysParamConfig);
        return R.result("101");
    }

    /**
     * @param itemCode
     * @return
     */
    @Override
    @Cacheable(value  = "system:sysParam",key="#itemCode")
    public SysParamConfig querySysConfigByCode(String itemCode) {
        return paramConfigDao.queryByCode(itemCode);
    }

    /**
     * 保存通知
     *
     * @param notice 通知
     * @return {@link JSONObject }
     */
    @Override
    public SysNotice saveNotice(SysNotice notice) {
        if(notice.getCreateDate() == null){
            notice.setCreateDate(DateUtil.toLocalDateTime(DateUtil.date()));
        }
        notice.setUpdateDate(DateUtil.toLocalDateTime(DateUtil.date()));
        return sysNoticeDao.saveOrUpdateByNotNullProperties(notice);
    }

    /**
     * 查询通知
     *
     * @param notice 通知
     * @return {@link Page }<{@link SysNotice }>
     */
    @Override
    public Page<SysNotice> queryNotice(JSONObject notice) {
        Pageable pageable = PageLimit.pageable(notice,Sort.by(Sort.Direction.DESC,"updateDate"));
        return sysNoticeDao.findAll(FenixSpecification.of(builder ->builder.andLike("titleName",notice.getString("titleName"),
                StrUtil.isNotBlank(notice.getString("titleName"))).build()),pageable);
    }

    /**
     * 删除通知
     *
     * @param notice 通知
     * @return {@link JSONObject }
     */
    @Override
    public JSONObject deleteNotice(List<SysNotice> notice) {
        sysNoticeDao.deleteAllInBatch(notice);
        return R.result("101");
    }

    /**
     * 获取主办信息
     * @param jvmInfo jvm信息
     * @return jsonobject
     */
    private static JSONObject getHostInfo(JvmInfo jvmInfo) {
        HostInfo hostInfo = SystemUtil.getHostInfo();
        GlobalMemory memory = OshiUtil.getMemory();
        String total = convertFileSize( memory.getTotal());
        String used = convertFileSize(  memory.getTotal()-memory.getAvailable());
        String free = convertFileSize(memory.getAvailable());
        String rate = new BigDecimal(memory.getAvailable()).divide(new BigDecimal(memory.getTotal()),4, RoundingMode.HALF_UP)
                .multiply(new BigDecimal(100)).setScale(2,RoundingMode.HALF_UP)+"%";
        OsInfo osInfo = SystemUtil.getOsInfo();
        JSONObject hostJson = new JSONObject();
        hostJson.put("osName", osInfo.getName());
        hostJson.put("osVersion", osInfo.getVersion());
        hostJson.put("total", total);
        hostJson.put("used", used);
        hostJson.put("free", free);
        hostJson.put("rate", rate);
        hostJson.put("memoryTotal", memory.getTotal());
        hostJson.put("hostName", hostInfo.getName());
        hostJson.put("address", hostInfo.getAddress());
        hostJson.put("jdkName", jvmInfo.getName());
        hostJson.put("jdkVersion", jvmInfo.getVersion());
        hostJson.put("jdkVender", jvmInfo.getVendor());
        return hostJson;
    }

    /**
     * 字节转换
     *
     * @param size 字节大小
     * @return 转换后值
     */
    public static String convertFileSize(long size) {
        long kb = 1024;
        long mb = kb * 1024;
        long gb = mb * 1024;
        if (size >= gb) {
            return String.format("%.1f GB", (float) size / gb);
        } else if (size >= mb) {
            float f = (float) size / mb;
            return String.format(f > 100 ? "%.0f MB" : "%.1f MB", f);
        } else if (size >= kb) {
            float f = (float) size / kb;
            return String.format(f > 100 ? "%.0f KB" : "%.1f KB", f);
        } else {
            return String.format("%d B", size);
        }
    }
}
